





<!DOCTYPE html>
<html class="writer-html5" lang="zh-CN" >
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Adding a Compiler Pass to Relay &mdash; tvm 0.8.dev1982 文档</title>
  

  
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
  <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/gallery.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
  <link rel="stylesheet" href="../../_static/css/tlcpack_theme.css" type="text/css" />

  
  
    <link rel="shortcut icon" href="../../_static/tvm-logo-square.png"/>
  

  
  
  
  
    
      <script type="text/javascript" id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
        <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
        <script src="../../_static/jquery.js"></script>
        <script src="../../_static/underscore.js"></script>
        <script src="../../_static/doctools.js"></script>
        <script src="../../_static/translations.js"></script>
    
    <script type="text/javascript" src="../../_static/js/theme.js"></script>

    
    <script type="text/javascript" src="../../_static/js/tlcpack_theme.js"></script>
    <link rel="index" title="索引" href="../../genindex.html" />
    <link rel="search" title="搜索" href="../../search.html" />
    <link rel="next" title="Bring Your Own Codegen To TVM" href="relay_bring_your_own_codegen.html" />
    <link rel="prev" title="向 Realy 中添加一个算子" href="relay_add_op.html" /> 
</head>

<body class="wy-body-for-nav">

   
  <div class="wy-grid-for-nav">
    
    
<header class="header">
    <div class="innercontainer">
      <div class="headerInner d-flex justify-content-between align-items-center">
          <div class="headerLogo">
               <a href="https://tvm.apache.org/"><img src=https://tvm.apache.org/assets/images/logo.svg alt="logo"></a>
          </div>

          <div id="headMenu" class="headerNav">
            <button type="button" id="closeHeadMenu" class="navCloseBtn"><img src="../../_static/img/close-icon.svg" alt="Close"></button>
             <ul class="nav">
                <li class="nav-item">
                   <a class="nav-link" href=https://tvm.apache.org/community>Community</a>
                </li>
                <li class="nav-item">
                   <a class="nav-link" href=https://tvm.apache.org/download>Download</a>
                </li>
                <li class="nav-item">
                   <a class="nav-link" href=https://tvm.apache.org/vta>VTA</a>
                </li>
                <li class="nav-item">
                   <a class="nav-link" href=https://tvm.apache.org/blog>Blog</a>
                </li>
                <li class="nav-item">
                   <a class="nav-link" href=https://tvm.apache.org/docs>Docs</a>
                </li>
                <li class="nav-item">
                   <a class="nav-link" href=https://tvmconf.org>Conference</a>
                </li>
                <li class="nav-item">
                   <a class="nav-link" href=https://github.com/apache/tvm/>Github</a>
                </li>
                <li class="nav-item">
                   <a class="nav-link" href=https://tvmchinese.github.io/declaration_zh_CN.html>About-Translators</a>
                </li>
             </ul>
               <div class="responsivetlcdropdown">
                 <button type="button" class="btn-link">
                   ASF
                 </button>
                 <ul>
                     <li>
                       <a href=https://apache.org/>Apache Homepage</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/licenses/>License</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/foundation/sponsorship.html>Sponsorship</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/security/>Security</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/foundation/thanks.html>Thanks</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/events/current-event>Events</a>
                     </li>
                     <li>
                       <a href=https://www.zhihu.com/column/c_1429578595417563136>Zhihu</a>
                     </li>
                 </ul>
               </div>
          </div>
            <div class="responsiveMenuIcon">
              <button type="button" id="menuBtn" class="btn-menu"><img src="../../_static/img/menu-icon.svg" alt="Menu Icon"></button>
            </div>

            <div class="tlcDropdown">
              <div class="dropdown">
                <button type="button" class="btn-link dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                  ASF
                </button>
                <div class="dropdown-menu dropdown-menu-right">
                  <ul>
                     <li>
                       <a href=https://apache.org/>Apache Homepage</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/licenses/>License</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/foundation/sponsorship.html>Sponsorship</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/security/>Security</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/foundation/thanks.html>Thanks</a>
                     </li>
                     <li>
                       <a href=https://www.apache.org/events/current-event>Events</a>
                     </li>
                     <li>
                       <a href=https://www.zhihu.com/column/c_1429578595417563136>Zhihu</a>
                     </li>
                  </ul>
                </div>
              </div>
          </div>
       </div>
    </div>
 </header>
 
    <nav data-toggle="wy-nav-shift" class="wy-nav-side fixed">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search" >
          

          
            <a href="../../index.html">
          

          
            
            <img src="../../_static/tvm-logo-small.png" class="logo" alt="Logo"/>
          
          </a>

          
            
            
                <div class="version">
                  0.8.dev1982
                </div>
            
          

          
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

          
        </div>

        
        <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
          
            
            
              
            
            
              <p class="caption" role="heading"><span class="caption-text">如何开始</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../install/index.html">安装 TVM</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../contribute/index.html">贡献者指南</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">用户引导</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../tutorial/index.html">User Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../how_to/index.html">How To Guides</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">开发者引导</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../tutorial/index.html">Developer Tutorial</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="how_to.html">开发者指南</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="relay_add_op.html">向 Realy 中添加一个算子</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">Adding a Compiler Pass to Relay</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#ast-traversers">AST Traversers</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#expression-visitors">Expression Visitors</a></li>
<li class="toctree-l4"><a class="reference internal" href="#expression-mutators">Expression Mutators</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#example-constant-folding">Example: Constant Folding</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#the-constantchecker-visitor">The <code class="docutils literal notranslate"><span class="pre">ConstantChecker</span></code> Visitor</a></li>
<li class="toctree-l4"><a class="reference internal" href="#the-constantfolder-mutator">The <code class="docutils literal notranslate"><span class="pre">ConstantFolder</span></code> Mutator</a></li>
<li class="toctree-l4"><a class="reference internal" href="#registering-a-pass-with-the-pass-manager">Registering a Pass with the Pass Manager</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="relay_bring_your_own_codegen.html">Bring Your Own Codegen To TVM</a></li>
<li class="toctree-l2"><a class="reference internal" href="pytest_target_parametrization.html">Python Target Parametrization</a></li>
</ul>
</li>
</ul>
<p class="caption" role="heading"><span class="caption-text">架构指南</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../arch/index.html">Design and Architecture</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">主题引导</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../topic/microtvm/index.html">microTVM：裸机使用TVM</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../topic/vta/index.html">VTA: Versatile Tensor Accelerator</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">参考指南</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../reference/langref/index.html">语言参考</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../reference/api/python/index.html">Python API</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../reference/api/links.html">Other APIs</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../reference/publications.html">Publications</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../genindex.html">索引</a></li>
</ul>

            
          
        </div>
        
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
      
      <nav class="wy-nav-top" aria-label="top navigation" data-toggle="wy-nav-top">
        
            <div class="togglemenu">

            </div>
            <div class="nav-content">
              <!-- tvm -->
              Table of content
            </div>
        
      </nav>


      <div class="wy-nav-content">
        
        <div class="rst-content">
        

          




















<div role="navigation" aria-label="breadcrumbs navigation">

  <ul class="wy-breadcrumbs">
    
      <li><a href="../../index.html">Docs</a> <span class="br-arrow">></span></li>
        
          <li><a href="how_to.html">开发者指南</a> <span class="br-arrow">></span></li>
        
      <li>Adding a Compiler Pass to Relay</li>
    
    
      <li class="wy-breadcrumbs-aside">
        
            
            <a href="../../_sources/dev/how_to/relay_add_pass.rst.txt" rel="nofollow"> <img src="../../_static//img/source.svg" alt="viewsource"/></a>
          
        
      </li>
    
  </ul>

  
  <hr/>
</div>
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
            
  <div class="section" id="adding-a-compiler-pass-to-relay">
<span id="relay-add-pass"></span><h1>Adding a Compiler Pass to Relay<a class="headerlink" href="#adding-a-compiler-pass-to-relay" title="永久链接至标题">¶</a></h1>
<p>Compiler passes are the primary interface for both extending Relay’s feature
set and for performing optimizations on Relay programs. By writing a compiler
pass, you can modify the AST or collect information about the AST,
depending on your goal. Indeed, some of Relay’s most important built-in
features (e.g., autodiff and type inference) are nothing more than “standard”
compiler passes.</p>
<p>At a high level, there are two key components to writing a pass:</p>
<ul class="simple">
<li><p>Creating one or more C++ classes that traverse the program</p></li>
<li><p>Wrapping the traversal implementation and its metadata in the pass manager API so it can neatly interface with the <a class="reference internal" href="../../arch/pass_infra.html#pass-infra"><span class="std std-ref">Pass Infrastructure</span></a></p></li>
</ul>
<p>To begin, we’ll give an overview of the key mechanisms for writing a compiler
pass. Then, we’ll walk through a concrete example of the constant-folding
pass in Relay.</p>
<div class="section" id="ast-traversers">
<h2>AST Traversers<a class="headerlink" href="#ast-traversers" title="永久链接至标题">¶</a></h2>
<p>The base class used to traverse Relay programs is <code class="docutils literal notranslate"><span class="pre">ExprFunctor</span></code>. The public
interface it provides is a <code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code> method that takes an expression and
zero or more arguments and returns an instance of some type. When you extend
this class, you define the AST traversal pattern by overriding
implementations of <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> for each type of expression.</p>
<p>The relation between <code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code> and <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> has to do with
dispatch. Each <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> definition targets a specific type of
expression, but you don’t always know which node type you’ll be visiting.
To remedy this, <code class="docutils literal notranslate"><span class="pre">ExprFunctor</span></code> provides a <code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code> function which
routes from the given expression to the <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> case that handles it.
Although C++ already provides dynamic dispatch, <code class="docutils literal notranslate"><span class="pre">ExprFunctor</span></code> defines its
own vtable, which <code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code> uses. By defining our own vtable, we have
more control over dispatch. For example, if we wanted to define a
<code class="docutils literal notranslate"><span class="pre">PrintVisitor</span></code> traverser that printed “Here” before every visit, we
could override <code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code>:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">PrintVisitor</span><span class="o">::</span><span class="n">VisitExpr</span><span class="p">(</span><span class="k">const</span> <span class="n">Expr</span><span class="o">&amp;</span> <span class="n">expr</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&quot;Here&quot;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
  <span class="n">ExprFunctor</span><span class="o">::</span><span class="n">VisitExpr</span><span class="p">(</span><span class="n">expr</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">ExprFunctor</span></code> itself is a very general class, which is why more often than
not, you will be extending <code class="docutils literal notranslate"><span class="pre">ExprVisitor</span></code> or <code class="docutils literal notranslate"><span class="pre">ExprMutator</span></code>. These classes
extend <code class="docutils literal notranslate"><span class="pre">ExprFunctor</span></code> and provide default implementations of <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code>
that capture common traversal patterns for each expression type. Having these
default implementations means we only need to provide overriding
implementations for the expression types where we want different behavior. We
describe each subclass on its own in the following sections.</p>
<div class="section" id="expression-visitors">
<h3>Expression Visitors<a class="headerlink" href="#expression-visitors" title="永久链接至标题">¶</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">ExprVisitor</span></code> is for passes that don’t modify the program and instead
perform program analyses and collect information. With this class,
<code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code> and the private counterparts return nothing. The <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code>
implementations provided by this class simply visit all of the expression’s
fields that are expressions. The default implementation for <code class="docutils literal notranslate"><span class="pre">IfNode</span></code> is
shown below.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">ExprVisitor</span><span class="o">::</span><span class="n">VisitExpr_</span><span class="p">(</span><span class="k">const</span> <span class="n">IfNode</span><span class="o">*</span> <span class="n">op</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">this</span><span class="o">-&gt;</span><span class="n">VisitExpr</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">cond</span><span class="p">);</span>
  <span class="n">this</span><span class="o">-&gt;</span><span class="n">VisitExpr</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">true_branch</span><span class="p">);</span>
  <span class="n">this</span><span class="o">-&gt;</span><span class="n">VisitExpr</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">false_branch</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Note that we’re calling <code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code> and not <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> here, so we can
use the vtable in <code class="docutils literal notranslate"><span class="pre">ExprFunctor</span></code> for routing.</p>
<p>Now, if we wanted to write a class <code class="docutils literal notranslate"><span class="pre">CallChecker</span></code> that checks if any
function calls appear in the program, we would only need to extend
<code class="docutils literal notranslate"><span class="pre">ExprVisitor</span></code> and define the following <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> method:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">VisitExpr_</span><span class="p">(</span><span class="k">const</span> <span class="n">CallNode</span><span class="o">*</span> <span class="n">n</span><span class="p">)</span> <span class="n">final</span> <span class="p">{</span>
  <span class="n">result_</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>where <code class="docutils literal notranslate"><span class="pre">result_</span></code> is a field. In this case, we don’t need to further recurse
on the fields of the <code class="docutils literal notranslate"><span class="pre">CallNode</span></code>, because <code class="docutils literal notranslate"><span class="pre">result_</span></code> is already true and we
now know the original expression contains a call. To make this visitor
usable, we would provide the following public method:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">Check</span><span class="p">(</span><span class="k">const</span> <span class="n">Expr</span><span class="o">&amp;</span> <span class="n">expr</span><span class="p">)</span> <span class="n">final</span> <span class="p">{</span>
  <span class="n">result_</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
  <span class="n">VisitExpr</span><span class="p">(</span><span class="n">expr</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">result_</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>And that’s all we need. It is very common to define a public interface that
performs some bookkeeping before invoking the top-level recursion. We could
of course further wrap the API by making a standalone procedure that creates
a <code class="docutils literal notranslate"><span class="pre">CallChecker</span></code> instance and calls <code class="docutils literal notranslate"><span class="pre">Check</span></code> on it, but the takeaway is
that we’ve achieved our goal with very little effort.</p>
</div>
<div class="section" id="expression-mutators">
<h3>Expression Mutators<a class="headerlink" href="#expression-mutators" title="永久链接至标题">¶</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">ExprMutator</span></code> is for passes that transform the program in some way. With
this class, <code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code> and its private counterparts return <code class="docutils literal notranslate"><span class="pre">Expr</span></code>. The
default <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> implementations provided by this class visit all of
the expression’s fields that are expressions and set the fields to be the
result of visiting them. The default implementation for <code class="docutils literal notranslate"><span class="pre">TupleGetItemNode</span></code>
is shown below.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">Expr</span> <span class="n">ExprMutator</span><span class="o">::</span><span class="n">VisitExpr_</span><span class="p">(</span><span class="k">const</span> <span class="n">TupleGetItemNode</span><span class="o">*</span> <span class="n">g</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">auto</span> <span class="n">t</span> <span class="o">=</span> <span class="n">this</span><span class="o">-&gt;</span><span class="n">Mutate</span><span class="p">(</span><span class="n">g</span><span class="o">-&gt;</span><span class="n">tuple</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">g</span><span class="o">-&gt;</span><span class="n">tuple</span> <span class="o">==</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">GetRef</span><span class="o">&lt;</span><span class="n">Expr</span><span class="o">&gt;</span><span class="p">(</span><span class="n">g</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">TupleGetItem</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">g</span><span class="o">-&gt;</span><span class="n">index</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>There are a few things to notice here. First, <code class="docutils literal notranslate"><span class="pre">Mutate</span></code> is an alias for
<code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code> in <code class="docutils literal notranslate"><span class="pre">ExprMutator</span></code>. Second, we only return a new node if the
call to <code class="docutils literal notranslate"><span class="pre">Mutate</span></code> modified the <code class="docutils literal notranslate"><span class="pre">tuple</span></code> field. This method of update is
called a functional update and doing so avoids unnecessary allocations.</p>
<p>One feature <code class="docutils literal notranslate"><span class="pre">ExprMutator</span></code> has that <code class="docutils literal notranslate"><span class="pre">ExprVisitor</span></code> doesn’t is a built-in
<code class="docutils literal notranslate"><span class="pre">memo_</span></code> field for caching results. It makes sense that <code class="docutils literal notranslate"><span class="pre">ExprMutator</span></code> has
a memoizer, because we know which types of results we’re caching (i.e.,
<code class="docutils literal notranslate"><span class="pre">Expr</span></code>), whereas the visit methods of <code class="docutils literal notranslate"><span class="pre">ExprVisitor</span></code> don’t return
anything. Usually, when we want to cache results in a subclass of
<code class="docutils literal notranslate"><span class="pre">ExprVisitor</span></code>, we need to define the cache ourselves.</p>
<p>Now, if we wanted to write a class <code class="docutils literal notranslate"><span class="pre">IfCollapser</span></code> that replaces every if
statement with its true branch, we would override <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> for
<code class="docutils literal notranslate"><span class="pre">IfNode</span></code>:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">Expr</span> <span class="n">ExprMutator</span><span class="o">::</span><span class="n">VisitExpr_</span><span class="p">(</span><span class="k">const</span> <span class="n">IfNode</span><span class="o">*</span> <span class="n">op</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="n">this</span><span class="o">-&gt;</span><span class="n">Mutate</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">true_branch</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Note that the returned expression will not necessarily be an <code class="docutils literal notranslate"><span class="pre">IfNode</span></code>, and
this is fine, because the return type is <code class="docutils literal notranslate"><span class="pre">Expr</span></code>. Now, we create the public
interface:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">Expr</span> <span class="nf">CollapseIfs</span><span class="p">(</span><span class="k">const</span> <span class="n">Expr</span><span class="o">&amp;</span> <span class="n">expr</span><span class="p">)</span> <span class="n">final</span> <span class="p">{</span>
  <span class="k">return</span> <span class="n">this</span><span class="o">-&gt;</span><span class="n">Mutate</span><span class="p">(</span><span class="n">expr</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>With this mutator, we didn’t need to do any bookkeeping, but we still want to
follow the convention of having a descriptive method as the interface.</p>
</div>
</div>
<div class="section" id="example-constant-folding">
<h2>Example: Constant Folding<a class="headerlink" href="#example-constant-folding" title="永久链接至标题">¶</a></h2>
<p>In order to better understand the process of writing a pass, we will look at
the constant folding pass (found in <a class="reference external" href="https://github.com/apache/tvm/blob/main/src/relay/transforms/fold_constant.cc">src/relay/transforms/fold_constant.cc</a>)
as a guide, because it is a relatively simple pass that incorporates
both types of traversals.</p>
<p>Constant folding involves evaluating expressions in the program that only
involve constant values, then replacing those expressions with the result
of evaluating them. The goal of this pass is to frontload all of the
computations that we can. To achieve this, the constant folding pass makes
use of a visitor (<code class="docutils literal notranslate"><span class="pre">ConstantChecker</span></code>) and a mutator (<code class="docutils literal notranslate"><span class="pre">ConstantFolder</span></code>).</p>
<div class="section" id="the-constantchecker-visitor">
<h3>The <code class="docutils literal notranslate"><span class="pre">ConstantChecker</span></code> Visitor<a class="headerlink" href="#the-constantchecker-visitor" title="永久链接至标题">¶</a></h3>
<p>This visitor is used to check if an expression is constant. In Relay, we
define an expression to be constant if it is a <code class="docutils literal notranslate"><span class="pre">ConstantNode</span></code> or it is a
<code class="docutils literal notranslate"><span class="pre">TupleNode</span></code> with only constant fields.</p>
<p>We use a <code class="docutils literal notranslate"><span class="pre">memo_</span></code> field to map from nodes to whether they are constant and
to cache these results. Below are the <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> definitions in the
<code class="docutils literal notranslate"><span class="pre">ConstantChecker</span></code>.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">VisitExpr_</span><span class="p">(</span><span class="k">const</span> <span class="n">ConstantNode</span><span class="o">*</span> <span class="n">n</span><span class="p">)</span> <span class="n">final</span> <span class="p">{</span>
  <span class="n">memo_</span><span class="p">[</span><span class="n">GetRef</span><span class="o">&lt;</span><span class="n">Constant</span><span class="o">&gt;</span><span class="p">(</span><span class="n">n</span><span class="p">)]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">VisitExpr_</span><span class="p">(</span><span class="k">const</span> <span class="n">TupleNode</span><span class="o">*</span> <span class="n">n</span><span class="p">)</span> <span class="n">final</span> <span class="p">{</span>
  <span class="kt">bool</span> <span class="n">result</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
  <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">field</span> <span class="p">:</span> <span class="n">n</span><span class="o">-&gt;</span><span class="n">fields</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">Check</span><span class="p">(</span><span class="n">field</span><span class="p">))</span> <span class="p">{</span>
      <span class="n">result</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="n">memo_</span><span class="p">[</span><span class="n">GetRef</span><span class="o">&lt;</span><span class="n">Tuple</span><span class="o">&gt;</span><span class="p">(</span><span class="n">n</span><span class="p">)]</span> <span class="o">=</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The bookkeeping used to coordinate these definitions is a <code class="docutils literal notranslate"><span class="pre">Check</span></code> method
that returns whether the given expression is considered constant.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">Check</span><span class="p">(</span><span class="k">const</span> <span class="n">Expr</span><span class="o">&amp;</span> <span class="n">expr</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">const</span> <span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">memo_</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">expr</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">it</span> <span class="o">!=</span> <span class="n">memo_</span><span class="p">.</span><span class="n">end</span><span class="p">())</span>
    <span class="k">return</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">;</span>
  <span class="n">VisitExpr</span><span class="p">(</span><span class="n">expr</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">memo_</span><span class="p">[</span><span class="n">expr</span><span class="p">];</span>
<span class="p">}</span>
</pre></div>
</div>
<p>We don’t modify <code class="docutils literal notranslate"><span class="pre">memo_</span></code> for every node we encounter; instead we only modify
<code class="docutils literal notranslate"><span class="pre">memo_</span></code> when the encountered node could potentially be constant. Then we
rely on the default value being false when <code class="docutils literal notranslate"><span class="pre">memo_</span></code> doesn’t contain
<code class="docutils literal notranslate"><span class="pre">expr</span></code>.</p>
</div>
<div class="section" id="the-constantfolder-mutator">
<h3>The <code class="docutils literal notranslate"><span class="pre">ConstantFolder</span></code> Mutator<a class="headerlink" href="#the-constantfolder-mutator" title="永久链接至标题">¶</a></h3>
<p>This mutator performs the bulk of the constant folding pass and internally
uses <code class="docutils literal notranslate"><span class="pre">ConstantChecker</span></code>. In Relay, there are three node types that are
involved in constant folding: <code class="docutils literal notranslate"><span class="pre">LetNode</span></code>, <code class="docutils literal notranslate"><span class="pre">TupleItemGetNode</span></code>, and
<code class="docutils literal notranslate"><span class="pre">CallNode</span></code>. In the following paragraphs, we explain the roles of each in
the pass.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">Expr</span> <span class="nf">VisitExpr_</span><span class="p">(</span><span class="k">const</span> <span class="n">LetNode</span><span class="o">*</span> <span class="n">op</span><span class="p">)</span> <span class="n">final</span> <span class="p">{</span>
  <span class="n">Expr</span> <span class="n">value</span> <span class="o">=</span> <span class="n">this</span><span class="o">-&gt;</span><span class="n">Mutate</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">value</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">value</span><span class="p">.</span><span class="n">as</span><span class="o">&lt;</span><span class="n">ConstantNode</span><span class="o">&gt;</span><span class="p">())</span> <span class="p">{</span>
    <span class="n">memo_</span><span class="p">[</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">var</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">this</span><span class="o">-&gt;</span><span class="n">Mutate</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">body</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">Var</span> <span class="n">var</span> <span class="o">=</span> <span class="n">Downcast</span><span class="o">&lt;</span><span class="n">Var</span><span class="o">&gt;</span><span class="p">(</span><span class="n">this</span><span class="o">-&gt;</span><span class="n">Mutate</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">var</span><span class="p">));</span>
    <span class="n">Expr</span> <span class="n">body</span> <span class="o">=</span> <span class="n">this</span><span class="o">-&gt;</span><span class="n">Mutate</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">body</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">var</span><span class="p">.</span><span class="n">same_as</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">var</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
        <span class="n">value</span><span class="p">.</span><span class="n">same_as</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">value</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
        <span class="n">body</span><span class="p">.</span><span class="n">same_as</span><span class="p">(</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">body</span><span class="p">))</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">GetRef</span><span class="o">&lt;</span><span class="n">Expr</span><span class="o">&gt;</span><span class="p">(</span><span class="n">op</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">Let</span><span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">body</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>In the <code class="docutils literal notranslate"><span class="pre">LetNode</span></code> case, we first attempt to const-fold the value being bound
in the expression. If we can, then we populate <code class="docutils literal notranslate"><span class="pre">memo_</span></code> and return the
result of visiting the body—essentially, propagating the bound value to its
use sites in the body. If we can’t const-fold the bound value, we mimic the
default implementation.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">Expr</span> <span class="nf">VisitExpr_</span><span class="p">(</span><span class="k">const</span> <span class="n">TupleGetItemNode</span><span class="o">*</span> <span class="n">op</span><span class="p">)</span> <span class="n">final</span> <span class="p">{</span>
  <span class="n">Expr</span> <span class="n">res</span> <span class="o">=</span> <span class="n">ExprMutator</span><span class="o">::</span><span class="n">VisitExpr_</span><span class="p">(</span><span class="n">op</span><span class="p">);</span>
  <span class="n">op</span> <span class="o">=</span> <span class="n">res</span><span class="p">.</span><span class="n">as</span><span class="o">&lt;</span><span class="n">TupleGetItemNode</span><span class="o">&gt;</span><span class="p">();</span>
  <span class="k">if</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">*</span> <span class="n">tuple</span> <span class="o">=</span> <span class="n">op</span><span class="o">-&gt;</span><span class="n">tuple</span><span class="p">.</span><span class="n">as</span><span class="o">&lt;</span><span class="n">TupleNode</span><span class="o">&gt;</span><span class="p">())</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">tuple</span><span class="o">-&gt;</span><span class="n">fields</span><span class="p">[</span><span class="n">op</span><span class="o">-&gt;</span><span class="n">index</span><span class="p">];</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">res</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>In the <code class="docutils literal notranslate"><span class="pre">TupleItemGetNode</span></code> case, we check if <code class="docutils literal notranslate"><span class="pre">op-&gt;tuple</span></code> field is a
<code class="docutils literal notranslate"><span class="pre">TupleNode</span></code>. If so, we replace the tuple get with the field of the tuple
pointed to by <code class="docutils literal notranslate"><span class="pre">op-&gt;index</span></code>. The reason we need to check is because
<code class="docutils literal notranslate"><span class="pre">op-&gt;tuple</span></code> might evaluate to a tuple, without itself being a tuple.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">Expr</span> <span class="nf">VisitExpr_</span><span class="p">(</span><span class="k">const</span> <span class="n">CallNode</span><span class="o">*</span> <span class="n">call</span><span class="p">)</span> <span class="n">final</span> <span class="p">{</span>
  <span class="k">static</span> <span class="k">auto</span> <span class="n">op_stateful</span> <span class="o">=</span> <span class="n">Op</span><span class="o">::</span><span class="n">GetAttrMap</span><span class="o">&lt;</span><span class="n">TOpIsStateful</span><span class="o">&gt;</span><span class="p">(</span><span class="s">&quot;TOpIsStateful&quot;</span><span class="p">);</span>
  <span class="n">Expr</span> <span class="n">res</span> <span class="o">=</span> <span class="n">ExprMutator</span><span class="o">::</span><span class="n">VisitExpr_</span><span class="p">(</span><span class="n">call</span><span class="p">);</span>
  <span class="n">call</span> <span class="o">=</span> <span class="n">res</span><span class="p">.</span><span class="n">as</span><span class="o">&lt;</span><span class="n">CallNode</span><span class="o">&gt;</span><span class="p">();</span>
  <span class="c1">// We don&#39;t constant fold function with zero arguments.</span>
  <span class="c1">// This is a heuristic that is useful.</span>
  <span class="c1">// For example it is harmful to fold ones(shape=(4, 5)).</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">call</span><span class="o">-&gt;</span><span class="n">args</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">res</span><span class="p">;</span>
  <span class="k">const</span> <span class="n">OpNode</span><span class="o">*</span> <span class="n">op</span> <span class="o">=</span> <span class="n">call</span><span class="o">-&gt;</span><span class="n">op</span><span class="p">.</span><span class="n">as</span><span class="o">&lt;</span><span class="n">OpNode</span><span class="o">&gt;</span><span class="p">();</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">op</span> <span class="o">==</span> <span class="n">nullptr</span><span class="p">)</span> <span class="k">return</span> <span class="n">res</span><span class="p">;</span>
  <span class="c1">// skip stateful ops.</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">op_stateful</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">GetRef</span><span class="o">&lt;</span><span class="n">Op</span><span class="o">&gt;</span><span class="p">(</span><span class="n">op</span><span class="p">),</span> <span class="nb">false</span><span class="p">))</span> <span class="k">return</span> <span class="n">res</span><span class="p">;</span>
  <span class="kt">bool</span> <span class="n">all_const_args</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">Expr</span> <span class="nl">arg</span> <span class="p">:</span> <span class="n">call</span><span class="o">-&gt;</span><span class="n">args</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">checker_</span><span class="p">.</span><span class="n">Check</span><span class="p">(</span><span class="n">arg</span><span class="p">))</span> <span class="p">{</span>
      <span class="n">all_const_args</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">all_const_args</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">ConstEvaluate</span><span class="p">(</span><span class="n">res</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">res</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>In the <code class="docutils literal notranslate"><span class="pre">CallNode</span></code> case, we first use the <code class="docutils literal notranslate"><span class="pre">VisitExpr_</span></code> of <code class="docutils literal notranslate"><span class="pre">ExprMutator</span></code>
to visit the call, which const-folds all of the fields of the call. We use
<code class="docutils literal notranslate"><span class="pre">ExprMutator::VisitExpr_</span></code> instead of <code class="docutils literal notranslate"><span class="pre">VisitExpr</span></code>, because we want to
bypass the vtable (to avoid an infinite loop) and use the default
implementation provided by <code class="docutils literal notranslate"><span class="pre">ExprMutator</span></code>. Then we evaluate the call only if
all of the arguments are constant (using <code class="docutils literal notranslate"><span class="pre">ConstantChecker</span></code>). Evaluating the
call produces a <strong>value</strong>, so we use a helper method <code class="docutils literal notranslate"><span class="pre">ValueToExpr</span></code> to allow
us to place the evaluated expression back into the AST.</p>
<p>Now, we construct a more convenient interface <code class="docutils literal notranslate"><span class="pre">FoldConstant</span></code> for our constant
folder. <code class="docutils literal notranslate"><span class="pre">FoldConstant</span></code> is a standalone function outside of the <code class="docutils literal notranslate"><span class="pre">ConstantFolder</span></code>
class that takes an expression and internally creates and uses a
<code class="docutils literal notranslate"><span class="pre">ConstantFolder</span></code> instance (the full definition can be found in
<a class="reference external" href="https://github.com/apache/tvm/blob/main/src/relay/transforms/fold_constant.cc">src/relay/transforms/fold_constant.cc</a>).</p>
</div>
<div class="section" id="registering-a-pass-with-the-pass-manager">
<h3>Registering a Pass with the Pass Manager<a class="headerlink" href="#registering-a-pass-with-the-pass-manager" title="永久链接至标题">¶</a></h3>
<p><em>Note: please see the documentation on the :ref:`pass-infra` for more specific detail on this subject.</em></p>
<p>With the AST traversers written, the pass can be registered to become a TVM
API endpoint with the following code:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">namespace</span> <span class="n">transform</span> <span class="p">{</span>

<span class="n">Pass</span> <span class="n">FoldConstant</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">runtime</span><span class="o">::</span><span class="n">TypedPackedFunc</span><span class="o">&lt;</span><span class="n">Function</span><span class="p">(</span><span class="n">Function</span><span class="p">,</span> <span class="n">Module</span><span class="p">,</span> <span class="n">PassContext</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">pass_func</span> <span class="o">=</span>
    <span class="p">[</span><span class="o">=</span><span class="p">](</span><span class="n">Function</span> <span class="n">f</span><span class="p">,</span> <span class="n">Module</span> <span class="n">m</span><span class="p">,</span> <span class="n">PassContext</span> <span class="n">pc</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">Downcast</span><span class="o">&lt;</span><span class="n">Function</span><span class="o">&gt;</span><span class="p">(</span><span class="n">FoldConstant</span><span class="p">(</span><span class="n">f</span><span class="p">));</span>
  <span class="p">};</span>
  <span class="k">return</span> <span class="nf">CreateFunctionPass</span><span class="p">(</span><span class="n">pass_func</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="s">&quot;FoldConstant&quot;</span><span class="p">,</span> <span class="p">{});</span>
<span class="p">}</span>

<span class="p">}</span>  <span class="c1">// namespace transform</span>
</pre></div>
</div>
<p>If the <code class="docutils literal notranslate"><span class="pre">Pass</span></code> object produced by the above code is given to the pass infrastructure,
it will ensure that the AST traversal is applied to every function in the
given Relay module, which is the behavior one would expect for a constant folding
pass (it should fold all constants where possible).</p>
<p>The function <code class="docutils literal notranslate"><span class="pre">CreateFunctionPass</span></code>
allows for registering the optimization level of the pass (in this case, 2), which can
be used to group together passes based on their general utility, a name for the pass,
and any dependencies for the pass. A pass’s dependencies are given as a list of any passes
whose results are necessary to be able to run the current pass. <code class="docutils literal notranslate"><span class="pre">FoldConstant</span></code> does not
have any dependencies, but many Relay passes do depend on having type information,
so <code class="docutils literal notranslate"><span class="pre">InferType</span></code> is a common dependency; others may depend on the program’s being in
A-normal form, via the <code class="docutils literal notranslate"><span class="pre">ToANormalForm</span></code> pass.</p>
<p>Note that the <code class="docutils literal notranslate"><span class="pre">PassContext</span></code> object contains information a pass uses for
error reporting and configuration options; <code class="docutils literal notranslate"><span class="pre">FoldConstant</span></code> does not need
this information but other passes may reference their <code class="docutils literal notranslate"><span class="pre">PassContext</span></code> objects.</p>
<p>The pass can now be invoked via the pass infrastructure, though it’s a good idea to
also add a Python binding for the pass, as in this code snippet:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">TVM_REGISTER_GLOBAL</span><span class="p">(</span><span class="s">&quot;relay._transform.FoldConstant&quot;</span><span class="p">)</span>
<span class="p">.</span><span class="n">set_body_typed</span><span class="p">(</span><span class="n">FoldConstant</span><span class="p">);</span>
</pre></div>
</div>
<p>Once <code class="docutils literal notranslate"><span class="pre">Pass</span></code> objects are defined in the above fashion, they can be invoked using the
pass infrastructure’s <code class="docutils literal notranslate"><span class="pre">Sequential</span></code> construct, which takes a list of passes and applies
them in sequence to a Relay module, obtaining a transformed module as a result. For example,
the below code applies both the <code class="docutils literal notranslate"><span class="pre">FoldConstant</span></code> and <code class="docutils literal notranslate"><span class="pre">ToANormalForm</span></code> passes
(one after the other) to each function in <code class="docutils literal notranslate"><span class="pre">mod</span></code> and obtains a new module.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">seq</span> <span class="o">=</span> <span class="n">transform</span><span class="o">.</span><span class="n">Sequential</span><span class="p">([</span>
    <span class="n">relay</span><span class="o">.</span><span class="n">transform</span><span class="o">.</span><span class="n">FoldConstant</span><span class="p">(),</span>
    <span class="n">relay</span><span class="o">.</span><span class="n">transform</span><span class="o">.</span><span class="n">ToANormalForm</span><span class="p">()</span>
<span class="p">])</span>
<span class="n">new_mod</span> <span class="o">=</span> <span class="n">seq</span><span class="p">(</span><span class="n">mod</span><span class="p">)</span>
</pre></div>
</div>
<p>More detail about registration can be found in <a class="reference internal" href="../../arch/runtime.html#tvm-runtime-system"><span class="std std-ref">TVM runtime系统</span></a> and more
information about the pass manager interface can be found in <a class="reference internal" href="../../arch/pass_infra.html#pass-infra"><span class="std std-ref">Pass Infrastructure</span></a>.
Relay’s standard passes are listed in <a class="reference external" href="https://github.com/apache/tvm/blob/main/include/tvm/relay/transform.h">include/tvm/relay/transform.h</a> and implemented
in <a class="reference external" href="https://github.com/apache/tvm/tree/main/src/relay/transforms">src/relay/transforms/</a>.</p>
</div>
</div>
</div>


           </div>
           
          </div>
          

<footer>

    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="relay_bring_your_own_codegen.html" class="btn btn-neutral float-right" title="Bring Your Own Codegen To TVM" accesskey="n" rel="next">下一个 <span class="fa fa-arrow-circle-right"></span></a>
      
      
        <a href="relay_add_op.html" class="btn btn-neutral float-left" title="向 Realy 中添加一个算子" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> 上一个</a>
      
    </div>

<div id="button" class="backtop"><img src="../../_static//img/right.svg" alt="backtop"/> </div>
<section class="footerSec">
    <div class="footerHeader">
      <ul class="d-flex align-md-items-center justify-content-between flex-column flex-md-row">
        <li class="copywrite d-flex align-items-center">
          <h5 id="copy-right-info">© 2020 Apache Software Foundation | All right reserved</h5>
        </li>
      </ul>

    </div>

    <ul>
      <li class="footernote">Copyright © 2020 The Apache Software Foundation. Apache TVM, Apache, the Apache feather, and the Apache TVM project logo are either trademarks or registered trademarks of the Apache Software Foundation.</li>
    </ul>

</section>
</footer>
        </div>
      </div>

    </section>

  </div>
  

    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

  </body>
  <script type="text/javascript">
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script>

  
  
    
    <!-- Theme Analytics -->
    <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-75982049-2', 'auto');
    ga('send', 'pageview');
    </script>

    
   

</body>
</html>